home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1992 June: ROMin Holiday / ADC Developer CD (1992-06) (''ROMin Holiday'')_iso / Developer Connection - 06-1992.iso / Development Platforms / Apple II / Essentials / Technical.Notes / Pasc / TN.PASC.016 < prev    next >
Encoding:
Text File  |  1988-12-21  |  15.1 KB  |  423 lines  |  [TEXT/pdos]

  1. Apple II
  2. Technical Notes
  3. _____________________________________________________________________________
  4.                                                   Developer Technical Support
  5.  
  6.  
  7. Pascal
  8. #16:    Driver to Have Two Volumes on One 3.5" Disk
  9.  
  10. Revised by:    Guillermo Ortiz, Cheryl Ewy & Dan Strnad         November 1988
  11. Written by:    Guillermo Ortiz                                   October 1986
  12.  
  13. This Technical Note discusses how to install a driver to have more than one 
  14. volume on a 3.5" 800K disk under Apple II Pascal.
  15. _____________________________________________________________________________
  16.  
  17. For the sake of simplicity,.we will limit the discussion to the following 
  18. case: we want to have two 400K volumes on the boot 3.5" disk.  For such a 
  19. scenario, Unit #4 occupies the first 800 blocks and Unit #20 uses blocks 800 
  20. to 1599 as shown here:
  21.  
  22.            First Volume Unit #4               Second Volume Unit #4        
  23.  __|_________________________________|___________________________________|__
  24.    |       Blocks (0 .. 799)         |        Blocks (800 .. 1599)       |
  25.    
  26.  
  27.      +-- Directory Unit #4               +-- Directory Unit #20
  28.      |   blocks (2 .. 5)                 |   blocks (802 .. 805)
  29.      |                                   |
  30.  ___________________________________________________________________________
  31.  | |   |                             | |   |                             |
  32.  |_|___|_____________________________|_|___|_____________________________|__
  33.  | \                                 | \
  34.  |  \ Boot Blocks (0 .. 1)           |  \ Pseudo Boot Blocks (800 .. 801)
  35.  
  36.                       Figure 1-Block Diagram for 3.5" Disk
  37.  
  38. There are four calls a device driver has to handle, UNITCLEAR, UNITSTATUS, 
  39. UNITREAD, and UNITWRITE.  For the first one, our driver will only return since 
  40. the device is already on-line.  For a blocked device, UNITSTATUS returns the 
  41. number of blocks available, in this case UNITSTATUS (20) = 800.
  42.  
  43. In the case of UNITREAD and UNITWRITE, all the driver has to do is add the 
  44. offset of 800 to the number of the block requested then jump to the BIOS 
  45. routine with the unit number set to four.  Our driver is basically a 
  46. dispatcher that directs the disk access to the proper blocks.
  47.  
  48. When this driver is present, the application must be very careful about making 
  49. sure the right disk is in the drive when accessing the second volume; any 
  50. access to Unit #20 could damage a normal volume present in the drive.
  51.  
  52. Once the driver is ready, it is necessary to format a disk with the special 
  53. directories.  With the listings for the driver we have included the source of 
  54. a sample formatting program.
  55.  
  56. Once the disk is ready we proceed to transfer all system files to it including 
  57. SYSTEM.ATTACH, ATTACH.DRIVERS (containing our driver), and ATTACH.DATA.  This 
  58. last file reflects the following information:
  59.  
  60.     Driver Name - FAKEDISK  - Not Aligned
  61.     Attached to #20                                     {Can change if desired}
  62.     Unit #s to be init at boot time - 20
  63.     This driver CAN be placed in the first HiRes screen {Change if needed}
  64.     This driver CAN be placed in the second HiRes screen{Change if needed}
  65.     This driver does not use interrupts
  66.     Driver does not have transient initialization code
  67.  
  68. The code has comments that explain it fairly well; for more information on 
  69. drivers in general and how to use the attach tools please refer to Apple II 
  70. Pascal Device and Interrupt Support Tools.
  71.  
  72. ;
  73. ;       Disk Driver
  74. ;       by Guillermo Ortiz
  75. ;       03/25/86
  76. ;
  77. ;       This driver will allow splitting a 3.5 disk in two pieces of 400K
  78. ;       each, therefore permitting more than 77 files per disk. It
  79. ;       is required to "format" the disk with two directories, one at
  80. ;       block 0 .. 5 and the other at block 800 .. 805, each with a
  81. ;       length of 800 blocks. Names must be different!
  82.  
  83. ;       The ancient admonition:
  84. ;
  85. ;       This is a sample!
  86. ;       No claims are made regarding the fitness of this code for
  87. ;       any particular purpose. 
  88.  
  89. ROUTINE .EQU    02              ; For indirect jumping
  90. RETURN  .EQU    04              ; Back to Pascal
  91. BUFF    .EQU    06              ; Where to put stuff
  92.  
  93.         .PROC   FAKEDISK 
  94.         
  95. ;       At this level we could have some code to differentiate
  96. ;       between different pseudo volumes if we had more than
  97. ;       two pseudo-volumes per disk.
  98. ;       In this example we use Unit # 20 for the second part.
  99. ;       Using units 13 and up let us keep the "standard" drives available
  100. ;       In any UNIT call X Register contains the type of call
  101. ;       as follows:
  102.  
  103.         CPX     #04
  104.         BEQ     STATUS          ; X = 4
  105.         CPX     #02
  106.         BEQ     INIT            ; X = 2         
  107.         
  108.         STA     TEMP1           
  109.         STY     TEMP1+1         ; Saving A, Y and X
  110.         STX     TEMP1+2         ;   for future use
  111.         
  112. ;       We make the assumption that the disk split is the 
  113. ;       System Volume, so we get the logical volume number for
  114. ;       Unit # 4 from the DISKNUM table;
  115. ;       see Apple // Pascal Device and Interrupt
  116. ;       Support Tools manual for details.
  117.  
  118.         TSX                     ; Gimmie the stack pointer
  119.         LDA     0FEB6           ; Logical volume for boot disk
  120.         STA     109,X           ;   so read from that disk
  121.         
  122. ;       Our fiddling is complete now let's finish checking
  123. ;       the call in order to make the jump
  124.         
  125.         LDA     TEMP1+2         ; X contains the call code
  126.         BEQ     READ            ; X = 0  
  127.         CMP     #01             
  128.         BEQ     WRITE           ; X = 1   
  129.         
  130. ;       Here we could have 
  131. ;       instructions to report some undefined control code.
  132. ;       This driver will only CRASH!!!
  133.  
  134.         BRK                     ; Bumm!!!
  135.         
  136. ;       Now the real stuff
  137.  
  138. READ    .EQU    *
  139.         JSR     SETUP           ; Modify the stack
  140.         LDY     #19.            ; Index for Reading from disk
  141.         BNE     GET             ; Nice way of jumping
  142.         
  143. WRITE   .EQU    *
  144.         JSR     SETUP           ; Modify the stack
  145.         LDY     #16.            ; Index for WRITE to CONSOLE
  146.         
  147. GET     LDA     @0E2,Y          ; $E2 contains a pointer to the jump vector
  148.         STA     ROUTINE         ; Set low byte of address
  149.         INY
  150.         LDA     @0E2,Y          ; Get high byte of address
  151.         STA     ROUTINE+1       ;   and set it off
  152.         
  153.         LDX     TEMP1+2         ; Restore
  154.         LDY     TEMP1+1         ;   all registers
  155.         LDA     TEMP1           ;     before jump
  156.         
  157.         JMP     @ROUTINE        ; and Go!
  158.         
  159.  
  160.  
  161. ;       INIT will only pass back the no_error IORESULT
  162.         
  163. INIT    .EQU    *
  164.         LDX     #00             ; No error
  165.         RTS                     ;   Go back
  166.         
  167. STATUS  PLA                     ; Get
  168.         STA     RETURN          ;   return
  169.         PLA                     ;     address
  170.         STA     RETURN+1
  171.         PLA                     ; Get 
  172.         STA     BUFF            ;   Pascal      
  173.         PLA                     ;     Buffer
  174.         STA     BUFF+1          ;       address
  175.         PLA                     ; Dump control
  176.         PLA                     ;   word
  177.         LDY     #00
  178.         LDA     #20             ; Set
  179.         STA     @BUFF,Y         ;   the number of blocks
  180.         INY                     ;     to
  181.         LDA     #03             ;       800
  182.         STA     @BUFF,Y
  183.         LDX     #00
  184.         LDA     RETURN+1        ; and
  185.         PHA
  186.         LDA     RETURN
  187.         PHA
  188.         RTS                     ;   Return!
  189.         
  190.         
  191. ;       To any request for READ/WRITE we'll add 800 to the
  192. ;       number of the block needed.
  193.         
  194. SETUP   .EQU    *
  195.         LDA     103,X           ; Get Block number low
  196.         CLC                     ; Set up for addition
  197.         ADC     #20             ;   Offset block count by 800
  198.         STA     103,X           ;     and restore
  199.         LDA     104,X           ; Get Block number high
  200.         ADC     #03             ;   800 = $320
  201.         STA     104,X           ;     and restore
  202.         RTS                     ; Go back
  203.         
  204. TEMP1   .BLOCK  3               ; Temporary storage area
  205.  
  206.  
  207.         .END
  208.  
  209. The driver requires that the disk be formatted in a special way.  Run the 
  210. following program to create your volume.
  211.  
  212. program REFORMAT;
  213.  
  214. {By Guillermo Ortiz
  215.      03/27/86
  216. }
  217.  
  218.  
  219. {This program takes a newly formatted 3.5 disk and lays down two
  220.  directories transforming the volume into two 400K pseudo-volumes to be
  221.  used with the driver FAKEDISK which assigns Unit # 20 to the second 
  222.  part of the disk.
  223. }
  224.   
  225.  
  226. CONST   MAXDIR  = 77;   {Max number of files per volume}
  227.         VIDLENGTH = 7;  {Max chars in volume name}
  228.         TIDLENGTH = 15; {Max chars per file ID}
  229.         FBLKSIZE = 512; {Number of bytes per block}
  230.         DIRBLK = 2;     {We are reading the directory}
  231.         
  232. type    daterec = packed record
  233.                     month:0..12;        {0 --> Meaningless date}
  234.                     day:  0..31;        {Day of month}
  235.                     year:0..100         {100 --> dated volume is temp}
  236.                   end;
  237.                   
  238.         vid = string [vidlength];       {Volume ID}
  239.         dirrange = 0 .. maxdir;         {Number of files on disk}
  240.         tid = string[tidlength];        {File ID}
  241.         filekind = (untypedfile,xdskfile,codefile,textfile,infofile,
  242.                     datafile,graffile,fotofile,securdir);
  243.                     
  244. {Now the real directory layout}
  245.         direntry =
  246.           packed record
  247.             dfirstblk:integer;          {1st physical disk address}
  248.             dlastblock:integer;         {block after last used block}
  249.             case dfkind:filekind of
  250.               securdir,untypedfile:     {Volume info only in dir[0]}
  251.                (filler1: 0..2048;       {Waste 13 bits}
  252.                 dvid:    vid;           {Name of volume}
  253.                 deovblk: integer;       {Last block in volume}
  254.                 dnumfiles:dirrange;     {Number of files in directory}
  255.                 dloadtime:integer;      {Time of last access}
  256.                 dlastboot:daterec);     {Most recent date setting}
  257.               xdskfile,codefile,textfile,infofile,datafile,
  258.               graffile,fotofile:        {Regular file info}
  259.                (filler2: 0..1024;       {Waste 12 bits}
  260.                 status:  boolean;       {For filer wildcards}
  261.                 dtid:    tid;           {Name of file}
  262.                 dlastbyte:1..fblksize;  {Bytes in last block of file}
  263.                 daccess: daterec)       {Date of last modification}
  264.           end;  {Of the whole directory record}
  265.           
  266.         directory = array [dirrange] of direntry;
  267.         
  268.  
  269. var     dirinfo:directory;              {The directory goes here}
  270.         UNITNUM:INTEGER;
  271.         CH:CHAR;
  272.         
  273.  
  274. PROCEDURE DOSTUFF;
  275. {Function CHECK will read the directory from a freshly formatted
  276.  3.5 disk, then DOSTUFF will make changes so it has only 800 blocks and 
  277.  a name HALFONE: and will write it back to block 2; then we will 
  278.  change the name to HALFTWO: and will write to block 802 as 
  279.  the directory for our second pseudo-volume.
  280. }
  281.  
  282. BEGIN
  283.   with dirinfo[0] do
  284.     begin
  285.       deovblk:=800;  {Cut it in half}
  286.       dvid:='HALFONE';
  287.     end;
  288.   unitwrite(UNITNUM,dirinfo,sizeof(dirinfo),dirblk); {Put back main directory}
  289.   DIRINFO[0].DVID:='HALFTWO';
  290.   unitwrite(UNITNUM,dirinfo,sizeof(dirinfo),dirblk+800) {Write second dir.}
  291. end; {Of DOSTUFF}
  292.  
  293.  
  294. FUNCTION CHECK:BOOLEAN;
  295.  
  296. {Reads the directory from the target disk, if possible, warns the user
  297.  of the certain destruction of the current directory and checks the
  298.  size of the volume so that the program doesn't use other than 3.5
  299.  disks.
  300.  }
  301.  
  302.  
  303. BEGIN
  304.   CHECK:=FALSE;
  305.   DIRINFO[0].DLASTBLOCK:=-999;  {Make sure we read from a disk}
  306.   UNITREAD(UNITNUM,DIRINFO,SIZEOF(DIRINFO),DIRBLK);
  307.   IF DIRINFO[0].DLASTBLOCK= 6 THEN  {IS THIS A PASCAL DISK?}
  308.     BEGIN
  309.       IF DIRINFO[0].DEOVBLK <> 1600 THEN
  310.         BEGIN
  311.           WRITELN('SORRY THIS PROGRAM IS INTENDED FOR 3.5 DISKS ONLY');
  312.           EXIT(CHECK)
  313.         END;
  314.       WRITE('WE ARE ABOUT TO PERMANENTLY DESTROY    ');
  315.       WRITELN(DIRINFO[0].DVID,':');
  316.       WRITE('IS IT OK? --> ');
  317.       REPEAT 
  318.         READ(KEYBOARD,CH) 
  319.       UNTIL CH IN ['Y','N','n','y'];
  320.       WRITELN(CH);
  321.       IF CH IN ['Y','y'] THEN
  322.         CHECK:=TRUE
  323.     END
  324.   ELSE
  325.     BEGIN
  326.       WRITELN;
  327.       WRITELN;
  328.       WRITELN('CAN NOT READ DIRECTORY')
  329.     END
  330. END {OF CHECK};
  331.  
  332.  
  333. PROCEDURE GETNUM;
  334.  
  335. {Prompts the user for the Unit Number of the target disk,
  336.  checks the validity of the input and returns when provided with
  337.  a reasonable value.
  338.  }
  339.  
  340. VAR     I:INTEGER;
  341.         
  342. BEGIN
  343.   WRITELN;
  344.   WRITELN('PLEASE ENTER THE NUMBER OF THE UNIT CONTAINING THE DISK');
  345.   WRITE('TO BE REFORMATTED (PRESS <ESCAPE> TO EXIT) --> ');
  346.   UNITNUM:=0;
  347.   REPEAT
  348.     BEGIN
  349.       WRITE(CHR(5));    {Cursor ON}
  350.       READ(CH);         {For the prompt}
  351.       WRITE(CHR(6));    {and then OFF for speed and elegance(?)}
  352.       IF EOLN THEN
  353.         IF (UNITNUM IN [4,5,9..12]) THEN
  354.           EXIT(GETNUM)
  355.         ELSE
  356.           FOR I:= 1 TO 32 - UNITNUM DO  {Kind of crude but ...}
  357.             WRITE(CHR(8));              {to go back to the same place}
  358.       IF ORD(CH) = 27 THEN
  359.         BEGIN
  360.           WRITELN;
  361.           WRITELN('YOU ASKED FOR IT!!!');
  362.           WRITE(CHR(5));        {Turn cursor ON before we exit}
  363.           EXIT(PROGRAM)
  364.         END;
  365.       IF (ORD(CH) = 8) AND (UNITNUM > 0) THEN
  366.         BEGIN
  367.           IF UNITNUM < 10 THEN
  368.             UNITNUM:=0
  369.           ELSE
  370.             UNITNUM:=UNITNUM DIV 10;
  371.           WRITE(CHR(8),' ',CHR(8))      {To delete previous entry}
  372.         END
  373.       ELSE
  374.         BEGIN
  375.           IF (UNITNUM = 0) AND (CH IN ['1','4','5','9']) THEN
  376.             UNITNUM:=ORD(CH)-ORD('0')
  377.           ELSE
  378.             IF (UNITNUM=1) AND (CH IN ['0','1','2']) THEN
  379.               UNITNUM:=10*UNITNUM+ORD(CH)-ORD('0')
  380.             ELSE
  381.               IF ORD(CH) > 31 THEN
  382.                 WRITE(CHR(8),' ',CHR(8))        {Unwanted stuff,so ...}
  383.         END                                     {get rid of it.       }
  384.     END
  385.   UNTIL FALSE;                                  {No Exit here.}
  386.   WRITELN
  387. END {OF GETNUM};
  388.  
  389.  
  390. BEGIN                                   {main}
  391.   WRITELN;
  392.   WRITELN;
  393.   WRITELN('WE ARE ABOUT TO REFORMAT A VOLUME SO IT WILL CONTAIN TWO');
  394.   WRITELN('400K PSEUDO-VOLUMES. MAKE SURE YOU MARK THE DISK CLEARLY');
  395.   WRITELN('SO YOU DON''T FORGET');
  396.   WRITELN;
  397.   WRITELN;
  398.   REPEAT
  399.     GETNUM
  400.   UNTIL CHECK;
  401.   DOSTUFF;
  402.   WRITE(CHR(5));                {Don't forget to turn cursor ON}
  403.   writeln;
  404.   WRITELN('AWAAAAAY!!!')
  405. end.
  406.  
  407. If two volumes are not enough, you can modify this example to support more 
  408. than two per disk; the key is to keep in mind that when the call comes to the 
  409. driver, the accumulator contains the number of the Unit the for which the call 
  410. is intended.  After checking this number the driver could decide what offset 
  411. it has to add to access the correct volume.
  412.  
  413. Of course the formatter program would have to change accordingly, laying down 
  414. the directories for the new volumes with the appropriate names and sizes.
  415.  
  416. The same scheme can be applied to any device that Pascal can directly 
  417. recognize (i.e., the Apple Memory Expansion Card, ProFile hard disk, etc.).
  418.  
  419.  
  420. Further Reference
  421. o    Apple II Pascal Device and Interrupt Support Tools
  422.  
  423.